package org.zoomdev.zoom.dao.configs;

import org.zoomdev.zoom.dao.SqlConfig;
import org.zoomdev.zoom.dao.driver.SqlDriver;
import org.zoomdev.zoom.dao.entity.Entity;
import org.zoomdev.zoom.dao.entity.Field2ColumnMappingConfig;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public final class Insert {

    public static final char COMMA = ',';  //comma
    private final SqlDriver driver;
    private final ArrayList<Field2ColumnMappingConfig> insertFields = new ArrayList<>(16);
    private final ArrayList<Object> values = new ArrayList<>(16);
    private final ArrayList<String> placeHolders = new ArrayList<>(16);
    private final ArrayList<String> columns = new ArrayList<>(16);

    public Insert(SqlDriver driver) {
        this.driver = driver;
    }

    public int setParameter(PreparedStatement stmt, int index) throws SQLException {
        for (int i = 0, c = values.size(); i < c; ++i) {
            Object value = values.get(i);
            Field2ColumnMappingConfig config = insertFields.get(i);
            if (value == null) {
                stmt.setNull(index++, config.getJdbcType());
            } else {
                config.setNonnullParameter(stmt, index++, value);
            }
        }
        return index;
    }

    public void clear() {
        insertFields.clear();
        values.clear();
        placeHolders.clear();
        columns.clear();
    }


    public void prepare(SqlConfig cfg, Entity<?> entity, Object data, boolean ignoreNull) {

        Field2ColumnMappingConfig[] toDatabases = entity.getToDatabases();
        for (Field2ColumnMappingConfig toDatabase : toDatabases) {
            String insertPlaceholder = toDatabase.getInsertPlaceholder();
            if (toDatabase.getInsertPlaceholder() != null) {
                if (!insertPlaceholder.isEmpty()) {
                    columns.add(toDatabase.getColumnName());
                    placeHolders.add(insertPlaceholder);
                }
            } else {
                Object value = toDatabase.get(data);
                if (value == null && ignoreNull) {
                    continue;
                }
                if (entity.getSplitColumn() == toDatabase) {
                    cfg.setTable(entity.getSplitTableRule().getTable(value));
                }
                columns.add(toDatabase.getColumnName());
                placeHolders.add("?");
                addValue(toDatabase, value);
            }
        }


        if (cfg.getTable() == null) {
            cfg.setTable(entity.getTableName());
        }
    }

    public String buildSql(SqlConfig cfg) {
        StringBuilder sql = cfg.getSqlBuilder();
        sql.append("INSERT INTO ");
        driver.protectTable(sql, cfg.getTable()).append(" (");
        boolean first = true;
        for (String column : columns) {
            if (first) {
                first = false;
            } else {
                sql.append(COMMA);
            }
            driver.protectColumn(sql, column);
        }
        sql.append(") VALUES (");
        first = true;
        for (String placeHolder : placeHolders) {
            if (first) {
                first = false;
            } else {
                sql.append(COMMA);
            }
            sql.append(placeHolder);
        }
        sql.append(')');

        return sql.toString();
    }

    public List<Object> getValues() {
        return values;
    }

    private void addValue(Field2ColumnMappingConfig field, Object value) {
        insertFields.add(field);
        values.add(value);
    }
}
